/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import checkNumberLength from './helpers/checkNumberLength.js'
import parseDigits from './helpers/parseDigits.js'
import formatNationalNumberUsingFormat from './helpers/formatNationalNumberUsingFormat.js'

export default function formatCompleteNumber(state, format, {
	metadata,
	shouldTryNationalPrefixFormattingRule,
	getSeparatorAfterNationalPrefix
}) {
	const matcher = new RegExp(`^(?:${format.pattern()})$`)
	if (matcher.test(state.nationalSignificantNumber)) {
		return formatNationalNumberWithAndWithoutNationalPrefixFormattingRule(
			state,
			format,
			{
				metadata,
				shouldTryNationalPrefixFormattingRule,
				getSeparatorAfterNationalPrefix
			}
		)
	}
}

export function canFormatCompleteNumber(nationalSignificantNumber, metadata) {
	return checkNumberLength(nationalSignificantNumber, metadata) === 'IS_POSSIBLE'
}

function formatNationalNumberWithAndWithoutNationalPrefixFormattingRule(state, format, {
	metadata,
	shouldTryNationalPrefixFormattingRule,
	getSeparatorAfterNationalPrefix
}) {
	// `format` has already been checked for `nationalPrefix` requirement.

	const {
		nationalSignificantNumber,
		international,
		nationalPrefix,
		carrierCode
	} = state

	// Format the number with using `national_prefix_formatting_rule`.
	// If the resulting formatted number is a valid formatted number, then return it.
	//
	// Google's AsYouType formatter is different in a way that it doesn't try
	// to format using the "national prefix formatting rule", and instead it
	// simply prepends a national prefix followed by a " " character.
	// This code does that too, but as a fallback.
	// The reason is that "national prefix formatting rule" may use parentheses,
	// which wouldn't be included has it used the simpler Google's way.
	//
	if (shouldTryNationalPrefixFormattingRule(format)) {
		const formattedNumber = formatNationalNumber(state, format, {
			useNationalPrefixFormattingRule: true,
			getSeparatorAfterNationalPrefix,
			metadata
		})
		if (formattedNumber) {
			return formattedNumber
		}
	}

	// Format the number without using `national_prefix_formatting_rule`.
	return formatNationalNumber(state, format, {
		useNationalPrefixFormattingRule: false,
		getSeparatorAfterNationalPrefix,
		metadata
	})
}

function formatNationalNumber(state, format, {
	metadata,
	useNationalPrefixFormattingRule,
	getSeparatorAfterNationalPrefix
}) {
	let formattedNationalNumber = formatNationalNumberUsingFormat(
		state.nationalSignificantNumber,
		format,
		{
			carrierCode: state.carrierCode,
			useInternationalFormat: state.international,
			withNationalPrefix: useNationalPrefixFormattingRule,
			metadata
		}
	)
	if (!useNationalPrefixFormattingRule) {
		if (state.nationalPrefix) {
			// If a national prefix was extracted, then just prepend it,
			// followed by a " " character.
			formattedNationalNumber = state.nationalPrefix +
				getSeparatorAfterNationalPrefix(format) +
				formattedNationalNumber
		} else if (state.complexPrefixBeforeNationalSignificantNumber) {
			formattedNationalNumber = state.complexPrefixBeforeNationalSignificantNumber +
				' ' +
				formattedNationalNumber
		}
	}
	if (isValidFormattedNationalNumber(formattedNationalNumber, state)) {
		return formattedNationalNumber
	}
}

// Check that the formatted phone number contains exactly
// the same digits that have been input by the user.
// For example, when "0111523456789" is input for `AR` country,
// the extracted `this.nationalSignificantNumber` is "91123456789",
// which means that the national part of `this.digits` isn't simply equal to
// `this.nationalPrefix` + `this.nationalSignificantNumber`.
//
// Also, a `format` can add extra digits to the `this.nationalSignificantNumber`
// being formatted via `metadata[country].national_prefix_transform_rule`.
// For example, for `VI` country, it prepends `340` to the national number,
// and if this check hasn't been implemented, then there would be a bug
// when `340` "area coude" is "duplicated" during input for `VI` country:
// https://github.com/catamphetamine/libphonenumber-js/issues/318
//
// So, all these "gotchas" are filtered out.
//
// In the original Google's code, the comments say:
// "Check that we didn't remove nor add any extra digits when we matched
// this formatting pattern. This usually happens after we entered the last
// digit during AYTF. Eg: In case of MX, we swallow mobile token (1) when
// formatted but AYTF should retain all the number entered and not change
// in order to match a format (of same leading digits and length) display
// in that way."
// "If it's the same (i.e entered number and format is same), then it's
// safe to return this in formatted number as nothing is lost / added."
// Otherwise, don't use this format.
// https://github.com/google/libphonenumber/commit/3e7c1f04f5e7200f87fb131e6f85c6e99d60f510#diff-9149457fa9f5d608a11bb975c6ef4bc5
// https://github.com/google/libphonenumber/commit/3ac88c7106e7dcb553bcc794b15f19185928a1c6#diff-2dcb77e833422ee304da348b905cde0b
//
function isValidFormattedNationalNumber(formattedNationalNumber, state) {
	return parseDigits(formattedNationalNumber) === state.getNationalDigits()
}